package com.bluetrum.abmate.viewmodels;

import android.util.Pair;
import android.util.Range;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;

import com.bluetrum.devicemanager.DeviceCommManager;
import com.bluetrum.devicemanager.cmd.Command;
import com.bluetrum.devicemanager.cmd.Request;
import com.bluetrum.devicemanager.cmd.payloadhandler.BaseEngineRangePayloadHandler;
import com.bluetrum.devicemanager.cmd.payloadhandler.BooleanPayloadHandler;
import com.bluetrum.devicemanager.cmd.payloadhandler.BytePayloadHandler;
import com.bluetrum.devicemanager.cmd.payloadhandler.ByteToIntegerPayloadHandler;
import com.bluetrum.devicemanager.cmd.payloadhandler.DeviceCapacitiesPayloadHandler;
import com.bluetrum.devicemanager.cmd.payloadhandler.FirmwareChecksumPayloadHandler;
import com.bluetrum.devicemanager.cmd.payloadhandler.IntegerPayloadHandler;
import com.bluetrum.devicemanager.cmd.payloadhandler.KeyPayloadHandler;
import com.bluetrum.devicemanager.cmd.payloadhandler.LeAudioBisListAddPayloadHandler;
import com.bluetrum.devicemanager.cmd.payloadhandler.LeAudioBisListDeletePayloadHandler;
import com.bluetrum.devicemanager.cmd.payloadhandler.MultipointPayloadHandler;
import com.bluetrum.devicemanager.cmd.payloadhandler.PowerPayloadHandler;
import com.bluetrum.devicemanager.cmd.payloadhandler.RemoteEqSettingPayloadHandler;
import com.bluetrum.devicemanager.cmd.payloadhandler.RemoteEqSettingsPayloadHandler;
import com.bluetrum.devicemanager.cmd.payloadhandler.ResponsePayloadHandler;
import com.bluetrum.devicemanager.cmd.payloadhandler.SpatialAudioModePayloadHandler;
import com.bluetrum.devicemanager.cmd.payloadhandler.StringPayloadHandler;
import com.bluetrum.devicemanager.cmd.payloadhandler.TlvResponsePayloadHandler;
import com.bluetrum.devicemanager.cmd.request.AncRequest;
import com.bluetrum.devicemanager.cmd.request.BassEngineRequest;
import com.bluetrum.devicemanager.cmd.request.KeyRequest;
import com.bluetrum.devicemanager.cmd.request.MultipointRequest;
import com.bluetrum.devicemanager.cmd.request.MusicControlRequest;
import com.bluetrum.devicemanager.cmd.request.TlvRequest;
import com.bluetrum.devicemanager.models.BassEngineRange;
import com.bluetrum.devicemanager.models.DeviceCapacities;
import com.bluetrum.devicemanager.models.DevicePower;
import com.bluetrum.devicemanager.models.LeAudioBisItem;
import com.bluetrum.devicemanager.models.Multipoint;
import com.bluetrum.devicemanager.models.RemoteEqSetting;
import com.bluetrum.devicemanager.models.SpatialAudioMode;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

import timber.log.Timber;

public class DefaultDeviceCommManager extends DeviceCommManager {

    /* 设备状态 */

    private final MutableLiveData<DevicePower> devicePower = new MutableLiveData<>(null);
    private final MutableLiveData<Integer> deviceFirmwareVersion = new MutableLiveData<>(null);
    private final MutableLiveData<String> deviceName = new MutableLiveData<>(null);
    private final MutableLiveData<RemoteEqSetting> deviceEqSetting = new MutableLiveData<>(null);
    private final MutableLiveData<Map<Integer, Integer>> deviceKeySettings = new MutableLiveData<>(null);
    private final MutableLiveData<Byte> deviceVolume = new MutableLiveData<>(null);
    private final MutableLiveData<Boolean> devicePlayState = new MutableLiveData<>(null);
    private final MutableLiveData<Byte> deviceWorkMode = new MutableLiveData<>(null);
    private final MutableLiveData<Boolean> deviceInEarStatus = new MutableLiveData<>(null);
    private final MutableLiveData<Byte> deviceLanguageSetting = new MutableLiveData<>(null);
    private final MutableLiveData<Boolean> deviceAutoAnswer = new MutableLiveData<>(null);
    private final MutableLiveData<Byte> deviceAncMode = new MutableLiveData<>(null);
    private final MutableLiveData<Boolean> deviceIsTws = new MutableLiveData<>(null);
    private final MutableLiveData<Boolean> deviceTwsConnected = new MutableLiveData<>(null);
    private final MutableLiveData<Boolean> deviceLedSwitch = new MutableLiveData<>(null);
    private final MutableLiveData<byte[]> deviceFwChecksum = new MutableLiveData<>(null);
    private final MutableLiveData<Integer> deviceAncGain = new MutableLiveData<>(null);
    private final MutableLiveData<Integer> deviceTransparencyGain = new MutableLiveData<>(null);
    private final MutableLiveData<Integer> deviceAncGainNum = new MutableLiveData<>(null);
    private final MutableLiveData<Integer> deviceTransparencyGainNum = new MutableLiveData<>(null);
    private final MutableLiveData<List<RemoteEqSetting>> deviceRemoteEqSettings = new MutableLiveData<>(null);
    private final MutableLiveData<Boolean> deviceLeftIsMainSide = new MutableLiveData<>(null);
    private final MutableLiveData<Integer> deviceProductColor = new MutableLiveData<>(null);
    private final MutableLiveData<SpatialAudioMode> deviceSpatialAudioMode = new MutableLiveData<>(null);
    private final MutableLiveData<Boolean> deviceMultipointStatus = new MutableLiveData<>(null);
    private final MutableLiveData<Multipoint> deviceMultipointInfo = new MutableLiveData<>(null);
//    private final MutableLiveData<> deviceMultipointEvent = new MutableLiveData<>(null);
    private final MutableLiveData<Boolean> deviceVoiceRecognitionStatus = new MutableLiveData<>(null);
    private final MutableLiveData<Boolean> deviceAncFadeStatus = new MutableLiveData<>(null);
    private final MutableLiveData<Boolean> deviceBassEngineStatus = new MutableLiveData<>(null);
    private final MutableLiveData<Integer> deviceBassEngineValue = new MutableLiveData<>(null);
    private final MutableLiveData<BassEngineRange> deviceBassEngineRange = new MutableLiveData<>(null);
    private final MutableLiveData<Boolean> deviceAntiWindNoise = new MutableLiveData<>(null);
    private final MutableLiveData<DeviceCapacities> deviceCapacities = new MutableLiveData<>(null);

    private final List<Pair<Date, LeAudioBisItem>> _leAudioBisList = new ArrayList<>();
    private final MutableLiveData<List<Pair<Date, LeAudioBisItem>>> deviceLeAudioBisList = new MutableLiveData<>(null);
    private final ReentrantLock leAudioBisListLock = new ReentrantLock();

    // Request结果（如果成功）反映到DeviceInfo
    private boolean enableRequestToDevInfo = true;
    private final Map<Byte, Byte> requestToDeviceInfoMap = new HashMap<>();
    private final Map<Byte, Map<Byte, Byte>> tlvRequestToDeviceInfoMap = new HashMap<>();

    public DefaultDeviceCommManager() {
        super();
        registerDefaultResponseCallables();
        registerDefaultNotificationCallables();
        registerDefaultDeviceInfoCallables();
        registerRequestToDeviceInfoMaps();
    }

    @Override
    public void sendRequest(@NonNull final Request request,
                            @Nullable final DeviceCommManager.RequestCallback requestCallback) {
        DeviceCommManager.RequestCallback callback = new RequestCallback() {
            @Override
            public void onComplete(@NonNull Request request, @Nullable Object result) {
                if (requestCallback != null) {
                    requestCallback.onComplete(request, result);
                }
                // 处理完Response，再看要不要将结果反应到DevInfo
                if (enableRequestToDevInfo) {
                    processRequestToDevInfo(request, result);
                }
            }
            @Override
            public void onTimeout(@NonNull Request request) {
                if (requestCallback != null) {
                    requestCallback.onTimeout(request);
                }
            }
        };
        super.sendRequest(request, callback);
    }

    private void processRequestToDevInfo(final Request request, final Object result) {
        // Update LiveData directly, or sendRequest to get latest status
        // Here choose the first one method

        final byte command = request.getCommand();

        // TlvResponsePayloadHandler.class
        if (request instanceof TlvRequest && result instanceof Map) {
            TlvRequest tlvRequest = (TlvRequest) request;
            Map<Byte, byte[]> tlvDataMap = tlvRequest.getTlvDataMap();

            Map<Byte, Boolean> tlvResult = (Map<Byte, Boolean>) result;

            // Key，不同按键没有对应deviceInfo，需要特殊处理
            if (request instanceof KeyRequest) {
                byte keyType = ((KeyRequest) request).getKeyType();
                Boolean keyResult = tlvResult.get(keyType);
                if (keyResult != null && keyResult) {
                    // Update all key settings, not for only one
                    HashMap<Integer, Integer> keySetting = new HashMap<>();
                    keySetting.put((int) keyType, (int) ((KeyRequest) request).getKeyFunction());
                    deviceKeySettingsChanged(keySetting);
                }
            } else {
                tlvResult.forEach((subCommand, subResult) -> {
                    // 如果命令执行成功
                    if (subResult) {
                        // 根据主命令，确定子命令对应的Info
                        Byte tlvInfoType = getTlvDeviceInfoType(command, subCommand);
                        byte[] value = tlvDataMap.get(subCommand);
                        if (tlvInfoType != null && value != null) {
                            processDeviceInfo(tlvInfoType, value);
                        }
                    }
                });
            }
        }
        // ResponsePayloadHandler.class
        else {
            // 获取Command -> DevInfo映射
            Byte infoType = getDeviceInfoType(command);
            if (infoType != null) {
                if (result instanceof Boolean && (boolean) result) {
                    processDeviceInfo(infoType, request.getPayload());
                }
            }
        }
    }

    public void enableRequestToDevInfo(boolean enable) {
        this.enableRequestToDevInfo = enable;
    }

    private Byte getDeviceInfoType(final byte command) {
        return requestToDeviceInfoMap.get(command);
    }

    public void registerRequestToDeviceInfoMap(final byte command, final byte deviceInfo) {
        Timber.d("registerCommandToDeviceInfoMap: %s -> %s", command, deviceInfo);
        requestToDeviceInfoMap.put(command, deviceInfo);
    }

    public void unregisterRequestToDeviceInfoMap(final byte command) {
        requestToDeviceInfoMap.remove(command);
    }

    private Byte getTlvDeviceInfoType(final byte command, final byte subCommand) {
        Map<Byte, Byte> subMap = tlvRequestToDeviceInfoMap.get(command);
        if (subMap != null) {
            return subMap.get(subCommand);
        }
        return null;
    }

    public void registerTlvRequestToDeviceInfoMap(final byte command, final byte subCommand, final byte deviceInfo) {
        Timber.d("registerTlvRequestToDeviceInfoMap: (%s, %s) -> %s", command, subCommand, deviceInfo);
        Map<Byte, Byte> subMap = tlvRequestToDeviceInfoMap.get(command);
        if (subMap == null) {
            subMap = new HashMap<>();
            tlvRequestToDeviceInfoMap.put(command, subMap);
        }
        subMap.put(subCommand, deviceInfo);
    }

    public void unregisterTlvRequestToDeviceInfoMap(final byte command, final byte subCommand) {
        Map<Byte, Byte> subMap = tlvRequestToDeviceInfoMap.get(command);
        if (subMap != null) {
            subMap.remove(subCommand);
            if (subMap.size() == 0) {
                tlvRequestToDeviceInfoMap.remove(command);
            }
        }
    }

    public void registerTlvRequestRangeToDeviceInfoMap(final byte command,
                                                       final Range<Byte> subCommandRange,
                                                       final byte deviceInfo) {
        byte lower = subCommandRange.getLower();
        byte upper = subCommandRange.getUpper();
        for (byte i = lower; i <= upper; i++) {
            registerTlvRequestToDeviceInfoMap(command, i, deviceInfo);
        }
    }

    public void unregisterTlvRequestRangeToDeviceInfoMap(final byte command,
                                                         final Range<Byte> subCommandRange) {
        byte lower = subCommandRange.getLower();
        byte upper = subCommandRange.getUpper();
        for (byte i = lower; i <= upper; i++) {
            unregisterTlvRequestToDeviceInfoMap(command, i);
        }
    }

    /* */

    private void deviceKeySettingsChanged(final Map<Integer, Integer> keySetting) {
        Map<Integer, Integer> keySettings = deviceKeySettings.getValue();
        if (keySettings != null) {
            keySettings.putAll(keySetting);
        } else {
            keySettings = keySetting;
        }
        deviceKeySettings.setValue(keySettings);
    }

    /* 回复数据处理 */

    private void registerDefaultResponseCallables() {
        registerResponseCallable(Command.COMMAND_DEVICE_INFO, ResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_EQ, ResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_AUTO_SHUTDOWN, ResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_FACTORY_RESET, ResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_WORK_MODE, ResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_IN_EAR_DETECT, ResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_LANGUAGE, ResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_FIND_DEVICE, ResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_AUTO_ANSWER, ResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_BLUETOOTH_NAME, ResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_LED_MODE, ResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_CLEAR_PAIR_RECORD, ResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_SPATIAL_AUDIO_MODE, ResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_LE_AUDIO_BIS_STATUS, ResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_LE_AUDIO_BIS_SELECT, ResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_ANTI_WIND_NOISE, ResponsePayloadHandler.class);

        registerResponseCallable(Command.COMMAND_MUSIC_CONTROL, TlvResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_KEY, TlvResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_MULTIPOINT, TlvResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_ANC, TlvResponsePayloadHandler.class);
        registerResponseCallable(Command.COMMAND_BASS_ENGINE, TlvResponsePayloadHandler.class);
    }

    private void registerDefaultNotificationCallables() {
        registerNotificationCallback(Command.NOTIFICATION_DEVICE_POWER, PowerPayloadHandler.class, devicePower::setValue);
        registerNotificationCallback(Command.NOTIFICATION_EQ_SETTING, RemoteEqSettingPayloadHandler.class, deviceEqSetting::setValue);
        registerNotificationCallback(Command.NOTIFICATION_KEY_SETTINGS, KeyPayloadHandler.class, this::deviceKeySettingsChanged);
        registerNotificationCallback(Command.NOTIFICATION_DEVICE_VOLUME, BytePayloadHandler.class, deviceVolume::setValue);
        registerNotificationCallback(Command.NOTIFICATION_PLAY_STATE, BooleanPayloadHandler.class, devicePlayState::setValue);
        registerNotificationCallback(Command.NOTIFICATION_WORK_MODE, BytePayloadHandler.class, deviceWorkMode::setValue);
        registerNotificationCallback(Command.NOTIFICATION_IN_EAR_STATUS, BooleanPayloadHandler.class, deviceInEarStatus::setValue);
        registerNotificationCallback(Command.NOTIFICATION_LANGUAGE_SETTING, BytePayloadHandler.class, deviceLanguageSetting::setValue);
        registerNotificationCallback(Command.NOTIFICATION_ANC_MODE, BytePayloadHandler.class, deviceAncMode::setValue);
        registerNotificationCallback(Command.NOTIFICATION_TWS_CONNECTED, BooleanPayloadHandler.class, deviceTwsConnected::setValue);
        registerNotificationCallback(Command.NOTIFICATION_LED_SWITCH, BooleanPayloadHandler.class, deviceLedSwitch::setValue);
        registerNotificationCallback(Command.NOTIFICATION_ANC_GAIN, ByteToIntegerPayloadHandler.class, deviceAncGain::setValue);
        registerNotificationCallback(Command.NOTIFICATION_TRANSPARENCY_GAIN, ByteToIntegerPayloadHandler.class, deviceTransparencyGain::setValue);
        registerNotificationCallback(Command.NOTIFICATION_MAIN_SIDE, BooleanPayloadHandler.class, deviceLeftIsMainSide::setValue);
        registerNotificationCallback(Command.NOTIFICATION_SPATIAL_AUDIO_MODE, SpatialAudioModePayloadHandler.class, deviceSpatialAudioMode::setValue);
        registerNotificationCallback(Command.NOTIFICATION_MULTIPOINT_STATUS, BooleanPayloadHandler.class, deviceMultipointStatus::setValue);
        registerNotificationCallback(Command.NOTIFICATION_MULTIPOINT_INFO, MultipointPayloadHandler.class, deviceMultipointInfo::setValue);
        registerNotificationCallback(Command.NOTIFICATION_VOICE_RECOGNITION, BooleanPayloadHandler.class, deviceVoiceRecognitionStatus::setValue);
        registerNotificationCallback(Command.NOTIFICATION_BASS_ENGINE_STATUS, BooleanPayloadHandler.class, deviceBassEngineStatus::setValue);
        registerNotificationCallback(Command.NOTIFICATION_LE_AUDIO_BIS_ADD, LeAudioBisListAddPayloadHandler.class, this::leAudioBisListAdd);
        registerNotificationCallback(Command.NOTIFICATION_LE_AUDIO_BIS_DELETE, LeAudioBisListDeletePayloadHandler.class, this::leAudioBisListDelete);
        registerNotificationCallback(Command.NOTIFICATION_ANTI_WIND_NOISE, BooleanPayloadHandler.class, deviceAntiWindNoise::setValue);
    }

    private void registerDefaultDeviceInfoCallables() {
        registerDeviceInfoCallback(Command.INFO_DEVICE_POWER, PowerPayloadHandler.class, devicePower::setValue);
        registerDeviceInfoCallback(Command.INFO_FIRMWARE_VERSION, IntegerPayloadHandler.class, deviceFirmwareVersion::setValue);
        registerDeviceInfoCallback(Command.INFO_BLUETOOTH_NAME, StringPayloadHandler.class, deviceName::setValue);
        registerDeviceInfoCallback(Command.INFO_EQ_SETTING, RemoteEqSettingPayloadHandler.class, deviceEqSetting::setValue);
        registerDeviceInfoCallback(Command.INFO_KEY_SETTINGS, KeyPayloadHandler.class, this::deviceKeySettingsChanged);
        registerDeviceInfoCallback(Command.INFO_DEVICE_VOLUME, BytePayloadHandler.class, deviceVolume::setValue);
        registerDeviceInfoCallback(Command.INFO_PLAY_STATE, BooleanPayloadHandler.class, devicePlayState::setValue);
        registerDeviceInfoCallback(Command.INFO_WORK_MODE, BytePayloadHandler.class, deviceWorkMode::setValue);
        registerDeviceInfoCallback(Command.INFO_IN_EAR_STATUS, BooleanPayloadHandler.class, deviceInEarStatus::setValue);
        registerDeviceInfoCallback(Command.INFO_LANGUAGE_SETTING, BytePayloadHandler.class, deviceLanguageSetting::setValue);
        registerDeviceInfoCallback(Command.INFO_AUTO_ANSWER, BooleanPayloadHandler.class, deviceAutoAnswer::setValue);
        registerDeviceInfoCallback(Command.INFO_ANC_MODE, BytePayloadHandler.class, deviceAncMode::setValue);
        registerDeviceInfoCallback(Command.INFO_IS_TWS, BooleanPayloadHandler.class, deviceIsTws::setValue);
        registerDeviceInfoCallback(Command.INFO_TWS_CONNECTED, BooleanPayloadHandler.class, deviceTwsConnected::setValue);
        registerDeviceInfoCallback(Command.INFO_LED_SWITCH, BooleanPayloadHandler.class, deviceLedSwitch::setValue);
        registerDeviceInfoCallback(Command.INFO_FW_CHECKSUM, FirmwareChecksumPayloadHandler.class, deviceFwChecksum::setValue);
        registerDeviceInfoCallback(Command.INFO_ANC_GAIN, ByteToIntegerPayloadHandler.class, deviceAncGain::setValue);
        registerDeviceInfoCallback(Command.INFO_TRANSPARENCY_GAIN, ByteToIntegerPayloadHandler.class, deviceTransparencyGain::setValue);
        registerDeviceInfoCallback(Command.INFO_ANC_GAIN_NUM, ByteToIntegerPayloadHandler.class, deviceAncGainNum::setValue);
        registerDeviceInfoCallback(Command.INFO_TRANSPARENCY_GAIN_NUM, ByteToIntegerPayloadHandler.class, deviceTransparencyGainNum::setValue);
        registerDeviceInfoCallback(Command.INFO_ALL_EQ_SETTINGS, RemoteEqSettingsPayloadHandler.class, deviceRemoteEqSettings::setValue);
        registerDeviceInfoCallback(Command.INFO_MAIN_SIDE, BooleanPayloadHandler.class, deviceLeftIsMainSide::setValue);
        registerDeviceInfoCallback(Command.INFO_PRODUCT_COLOR, IntegerPayloadHandler.class, deviceProductColor::setValue);
        registerDeviceInfoCallback(Command.INFO_SPATIAL_AUDIO_MODE, SpatialAudioModePayloadHandler.class, deviceSpatialAudioMode::setValue);
        registerDeviceInfoCallback(Command.INFO_MULTIPOINT_STATUS, BooleanPayloadHandler.class, deviceMultipointStatus::setValue);
        registerDeviceInfoCallback(Command.INFO_MULTIPOINT_INFO, MultipointPayloadHandler.class, deviceMultipointInfo::setValue);
        registerDeviceInfoCallback(Command.INFO_VOICE_RECOGNITION, BooleanPayloadHandler.class, deviceVoiceRecognitionStatus::setValue);
        registerDeviceInfoCallback(Command.INFO_ANC_FADE_STATUS, BooleanPayloadHandler.class, deviceAncFadeStatus::setValue);
        registerDeviceInfoCallback(Command.INFO_BASS_ENGINE_STATUS, BooleanPayloadHandler.class, deviceBassEngineStatus::setValue);
        registerDeviceInfoCallback(Command.INFO_BASS_ENGINE_VALUE, ByteToIntegerPayloadHandler.class, deviceBassEngineValue::setValue);
        registerDeviceInfoCallback(Command.INFO_BASS_ENGINE_RANGE, BaseEngineRangePayloadHandler.class, deviceBassEngineRange::setValue);
        registerDeviceInfoCallback(Command.INFO_ANTI_WIND_NOISE, BooleanPayloadHandler.class, deviceAntiWindNoise::setValue);
        registerDeviceInfoCallback(Command.INFO_DEVICE_CAPABILITIES, DeviceCapacitiesPayloadHandler.class, deviceCapacities::setValue);
    }

    private void registerRequestToDeviceInfoMaps() {
        registerRequestToDeviceInfoMap(Command.COMMAND_EQ, Command.INFO_EQ_SETTING);
        registerRequestToDeviceInfoMap(Command.COMMAND_WORK_MODE, Command.INFO_WORK_MODE);
        registerRequestToDeviceInfoMap(Command.COMMAND_IN_EAR_DETECT, Command.INFO_IN_EAR_STATUS);
        registerRequestToDeviceInfoMap(Command.COMMAND_LANGUAGE, Command.INFO_LANGUAGE_SETTING);
        registerRequestToDeviceInfoMap(Command.COMMAND_AUTO_ANSWER, Command.INFO_AUTO_ANSWER);
        registerRequestToDeviceInfoMap(Command.COMMAND_BLUETOOTH_NAME, Command.INFO_BLUETOOTH_NAME);
        registerRequestToDeviceInfoMap(Command.COMMAND_LED_MODE, Command.INFO_LED_SWITCH);
        registerRequestToDeviceInfoMap(Command.COMMAND_SPATIAL_AUDIO_MODE, Command.INFO_SPATIAL_AUDIO_MODE);
        registerRequestToDeviceInfoMap(Command.COMMAND_ANTI_WIND_NOISE, Command.INFO_ANTI_WIND_NOISE);

        registerTlvRequestToDeviceInfoMap(Command.COMMAND_MUSIC_CONTROL, MusicControlRequest.CONTROL_TYPE_VOLUME, Command.INFO_DEVICE_VOLUME);
        registerTlvRequestToDeviceInfoMap(Command.COMMAND_MULTIPOINT, MultipointRequest.MULTIPOINT_STATUS, Command.INFO_MULTIPOINT_STATUS);
        registerTlvRequestToDeviceInfoMap(Command.COMMAND_ANC, AncRequest.ANC_MODE, Command.INFO_ANC_MODE);
        registerTlvRequestToDeviceInfoMap(Command.COMMAND_ANC, AncRequest.ANC_NC_LEVEL, Command.INFO_ANC_GAIN);
        registerTlvRequestToDeviceInfoMap(Command.COMMAND_ANC, AncRequest.ANC_TRANSPARENCY_LEVEL, Command.INFO_TRANSPARENCY_GAIN);
        registerTlvRequestToDeviceInfoMap(Command.COMMAND_ANC, AncRequest.ANC_FADE, Command.INFO_ANC_FADE_STATUS);
        registerTlvRequestToDeviceInfoMap(Command.COMMAND_BASS_ENGINE, BassEngineRequest.BASE_ENGINE_STATUS, Command.INFO_BASS_ENGINE_STATUS);
        registerTlvRequestToDeviceInfoMap(Command.COMMAND_BASS_ENGINE, BassEngineRequest.BASE_ENGINE_VALUE, Command.INFO_BASS_ENGINE_VALUE);
        // Key
        registerTlvRequestRangeToDeviceInfoMap(
                Command.COMMAND_KEY,
                new Range<>(KeyRequest.KEY_LEFT_SINGLE_TAP, KeyRequest.KEY_RIGHT_LONG_PRESS),
                Command.INFO_KEY_SETTINGS
        );
    }

    private void leAudioBisListAdd(List<LeAudioBisItem> listAdd) {
        leAudioBisListLock.lock();
        Date now = new Date();
        if (listAdd != null && listAdd.size() > 0) {
            for (LeAudioBisItem newItem : listAdd) {
                boolean replaced = false;
                for (int i = 0; i < _leAudioBisList.size(); i++) {
                    LeAudioBisItem oldItem = _leAudioBisList.get(i).second;
                    // 如果identifier相同，更新项
                    if (oldItem.getIdentifier() == newItem.getIdentifier()) {
                        Pair<Date, LeAudioBisItem> pair = new Pair<>(now, newItem);
                        _leAudioBisList.set(i, pair);
                        replaced = true;
                    }
                }
                if (!replaced) {
                    Pair<Date, LeAudioBisItem> pair = new Pair<>(now, newItem);
                    _leAudioBisList.add(pair);
                }
            }
            deviceLeAudioBisList.postValue(_leAudioBisList);
            leAudioBisListLock.unlock();
        }
    }

    private void leAudioBisListDelete(List<LeAudioBisItem> listDelete) {
        leAudioBisListLock.lock();
        for (LeAudioBisItem deleteItem : listDelete) {
            Iterator<Pair<Date, LeAudioBisItem>> iterator = _leAudioBisList.iterator();
            while (iterator.hasNext()) {
                LeAudioBisItem oldItem = iterator.next().second;
                // 如果identifier相同，删除项
                if (oldItem.getIdentifier() == deleteItem.getIdentifier()) {
                    iterator.remove();
                }
            }
        }
        deviceLeAudioBisList.postValue(_leAudioBisList);
        leAudioBisListLock.unlock();
    }

    /* 设备状态 */

    public LiveData<DevicePower> getDevicePower() {
        return devicePower;
    }

    public LiveData<Integer> getDeviceFirmwareVersion() {
        return deviceFirmwareVersion;
    }

    public LiveData<String> getDeviceName() {
        return deviceName;
    }

    public LiveData<RemoteEqSetting> getDeviceEqSetting() {
        return deviceEqSetting;
    }

    public LiveData<Map<Integer, Integer>> getDeviceKeySettings() {
        return deviceKeySettings;
    }

    public LiveData<Byte> getDeviceVolume() {
        return deviceVolume;
    }

    public LiveData<Boolean> getDevicePlayState() {
        return devicePlayState;
    }

    public LiveData<Byte> getDeviceWorkMode() {
        return deviceWorkMode;
    }

    public LiveData<Boolean> getDeviceInEarStatus() {
        return deviceInEarStatus;
    }

    public LiveData<Byte> getDeviceLanguageSetting() {
        return deviceLanguageSetting;
    }

    public LiveData<Boolean> getDeviceAutoAnswer() {
        return deviceAutoAnswer;
    }

    public LiveData<Byte> getDeviceAncMode() {
        return deviceAncMode;
    }

    public LiveData<Boolean> getDeviceIsTws() {
        return deviceIsTws;
    }

    public LiveData<Boolean> getDeviceTwsConnected() {
        return deviceTwsConnected;
    }

    public LiveData<Boolean> getDeviceLedSwitch() {
        return deviceLedSwitch;
    }

    public LiveData<byte[]> getDeviceFwChecksum() {
        return deviceFwChecksum;
    }

    public LiveData<Integer> getDeviceAncGain() {
        return deviceAncGain;
    }

    public LiveData<Integer> getDeviceTransparencyGain() {
        return deviceTransparencyGain;
    }

    public LiveData<Integer> getDeviceAncGainNum() {
        return deviceAncGainNum;
    }

    public LiveData<Integer> getDeviceTransparencyGainNum() {
        return deviceTransparencyGainNum;
    }

    public LiveData<List<RemoteEqSetting>> getDeviceRemoteEqSettings() {
        return deviceRemoteEqSettings;
    }

    public LiveData<Boolean> getDeviceLeftIsMainSide() {
        return deviceLeftIsMainSide;
    }

    public LiveData<Integer> getDeviceProductColor() {
        return deviceProductColor;
    }

    public LiveData<SpatialAudioMode> getDeviceSpatialAudioMode() {
        return deviceSpatialAudioMode;
    }

    public LiveData<Boolean> getDeviceMultipointStatus() {
        return deviceMultipointStatus;
    }

    public LiveData<Multipoint> getDeviceMultipointInfo() {
        return deviceMultipointInfo;
    }

    public LiveData<Boolean> getDeviceVoiceRecognitionStatus() {
        return deviceVoiceRecognitionStatus;
    }

    public LiveData<Boolean> getDeviceAncFadeStatus() {
        return deviceAncFadeStatus;
    }

    public LiveData<Boolean> getDeviceBassEngineStatus() {
        return deviceBassEngineStatus;
    }

    public LiveData<Integer> getDeviceBassEngineValue() {
        return deviceBassEngineValue;
    }

    public LiveData<BassEngineRange> getDeviceBassEngineRange() {
        return deviceBassEngineRange;
    }

    public MutableLiveData<List<Pair<Date, LeAudioBisItem>>> getDeviceLeAudioBisList() {
        return deviceLeAudioBisList;
    }

    public LiveData<Boolean> getDeviceAntiWindNoise() {
        return deviceAntiWindNoise;
    }

    public LiveData<DeviceCapacities> getDeviceCapacities() {
        return deviceCapacities;
    }

    public void resetDeviceStatus() {
        // 重置LiveData
        devicePower.postValue(null);
        deviceFirmwareVersion.postValue(null);
        deviceName.postValue(null);
        deviceEqSetting.postValue(null);
        deviceKeySettings.postValue(null);
        deviceVolume.postValue(null);
        devicePlayState.postValue(null);
        deviceWorkMode.postValue(null);
        deviceInEarStatus.postValue(null);
        deviceLanguageSetting.postValue(null);
        deviceAutoAnswer.postValue(null);
        deviceAncMode.postValue(null);
        deviceIsTws.postValue(null);
        deviceTwsConnected.postValue(null);
        deviceLedSwitch.postValue(null);
        deviceAncGain.postValue(null);
        deviceTransparencyGain.postValue(null);
        deviceAncGainNum.postValue(null);
        deviceTransparencyGainNum.postValue(null);
        deviceRemoteEqSettings.postValue(null);
        deviceLeftIsMainSide.postValue(null);
        deviceProductColor.postValue(null);
        deviceSpatialAudioMode.postValue(null);
        deviceMultipointStatus.postValue(null);
        deviceMultipointInfo.postValue(null);
//        deviceMultipointEvent.postValue(null);
        deviceVoiceRecognitionStatus.postValue(null);
        deviceAncFadeStatus.postValue(null);
        deviceBassEngineStatus.postValue(null);
        deviceBassEngineValue.postValue(null);
        deviceBassEngineRange.postValue(null);
        deviceLeAudioBisList.postValue(null);
        deviceAntiWindNoise.postValue(null);
        deviceCapacities.postValue(null);
    }

}
